/*
 * @Author: xiaohao
 * @Date: 2025-10-29 21:34:48
 * @LastEditors: xiaohao
 * @LastEditTime: 2025-11-05 21:28:38
 * @FilePath: /Project/ConcurrentMemoryPool/include/ConcurrentMemoryPool/Common.h
 * @Description:
 */
#pragma once
#include <iostream>
#include <vector>
#include <pthread.h>
#include <thread>
#include <mutex>
#include <ctime>
#include <assert.h>
#include <sys/mman.h> // 包含 mmap 系统调用的头文件
#include <unistd.h>   // 包含 brk 等系统调用的头文件
#include <algorithm>
#include <unordered_map>

#ifdef _WIN32
#include <windows.h> //  Windows 系统接口头文件
#endif

#ifdef _WIN64
typedef unsigned long long PAGE_ID; 
#elif _WIN32
typedef size_t PAGE_ID; 
#elif __linux__
typedef size_t PAGE_ID; 
#else
#error "Unsupported architecture"
#endif

static const size_t MAX_BYTES = 256 * 1024;      // 最大申请的内存块大小 256KB
static const size_t NFREE_LISTS = 208;           // 自由链表的数量：208个，对应不同大小的内存块分类
static const size_t NPAGES = 129;                // 总页数：129（128+1）
static const size_t PAGE_SHIFT = 13;             // 页大小 8KB = 2^13 字节
static const size_t PAGE_SIZE = 1 << PAGE_SHIFT; // 页大小：8KB

// 系统实际页大小（用于系统调用）
class SystemPageInfo
{
public:
    static size_t GetSize()
    {
        static size_t size = []()
        {
            long page_size = sysconf(_SC_PAGESIZE);
            return page_size > 0 ? static_cast<size_t>(page_size) : 4096;
        }();
        return size;
    }
};

/// @brief 向操作系统申请k页内存空间
/// @param kpage 申请的页数
/// @return 成功返回申请到的内存块首地址，失败返回nullptr
inline static void *SystemAlloc(size_t kpage)
{
    void *ptr = nullptr;
    size_t bytes = kpage * PAGE_SIZE; // 使用内存池页大小计算字节数

#ifdef _WIN32
    ptr = VirtualAlloc(
        nullptr,                  // 让系统自动分配地址
        kpage << PAGE_SHIFT,      // 申请大小：页数 × 8KB
        MEM_COMMIT | MEM_RESERVE, // 同时提交并保留内存
        PAGE_READWRITE            // 可读可写权限
    );

#elif __linux__
    // 计算需要多少系统页
    size_t system_page_size = SystemPageInfo::GetSize();
    size_t system_pages = (bytes + system_page_size - 1) / system_page_size;

    if (system_page_size == (size_t)-1)
    {
        perror("SystemAlloc: sysconf get page size failed");
        throw std::bad_alloc();
    }

    ptr = mmap(
        nullptr,                         // 内存起始地址：让内核自动选择（避免地址冲突）
        system_pages * system_page_size, // 映射区域总大小（字节）：等于“申请的页数(kpage) × 系统页大小(sys_page_size)”
        PROT_READ | PROT_WRITE,          // 内存权限：可读可写（满足一般内存操作需求）
        MAP_PRIVATE | MAP_ANONYMOUS,     // 映射类型：私有（修改仅本进程可见）+ 匿名（不关联文件，初始化为0）
        -1,                              // 文件描述符：匿名映射无需关联文件，固定为-1
        0                                // 文件偏移量：匿名映射无效，固定为0（必须页对齐）
    );

    // Linux下mmap失败返回MAP_FAILED，转换为nullptr统一判断
    if (ptr == MAP_FAILED)
    {
        perror("SystemAlloc: mmap failed");
        ptr = nullptr;
    }
#else
    #error "Unsupported OS"

#endif
    // 统一错误处理：所有平台返回nullptr则抛异常
    if (ptr == nullptr)
    {
        throw std::bad_alloc();
    }

    return ptr;
}

/// @brief 向操作系统释放k页内存空间
/// @param ptr  申请到的内存块首地址
/// @param kpage 申请的页数
inline static void SystemFree(void *ptr, size_t kpage)
{
    if (ptr == nullptr || kpage == 0)
        return; // 空指针直接返回，避免无效操作

#ifdef _WIN32
    (void)kpage; // 忽略参数
    // Windows：用VirtualFree释放内存
    VirtualFree(ptr, 0, MEM_RELEASE);

#elif __linux__
    // Linux：用munmap，匹配mmap的申请大小
    size_t bytes = kpage * PAGE_SIZE;
    size_t system_page_size = SystemPageInfo::GetSize();
    size_t system_pages = (bytes + system_page_size - 1) / system_page_size;

    munmap(ptr, system_pages * system_page_size);
#else
    #error "Unsupported OS"
#endif
}

inline void *&GetNextObj(void *obj)
{
    assert(obj != nullptr);

#ifndef NDEBUG
    const uintptr_t ptr_value = reinterpret_cast<uintptr_t>(obj); // 将指针 obj 转换为整数类型 uintptr_t
    assert((ptr_value % alignof(void *)) == 0 && "Pointer is not properly aligned");
#endif

    return *static_cast<void **>(obj);
}

// 管理切分好的小对象的自由链表
class FreeList
{
public:
    void Push(void *obj)
    {
        assert(obj != nullptr);
        // 头插
        GetNextObj(obj) = _freeList;
        _freeList = obj;

        ++_size;
    }

    void PushRange(void *start, void *end, size_t size)
    {
        assert(start != nullptr && end != nullptr);
        // 将[start, end]范围内的内存块链成一个链表
        GetNextObj(end) = _freeList;
        _freeList = start;

        _size += size;
    }

    void *Pop()
    {
        assert(_freeList != nullptr);
        // 头删
        void *obj = _freeList;
        _freeList = GetNextObj(obj);

        --_size;
        return obj;
    }

    void PopRange(void *&start, void *&end, size_t size)
    {
        assert(size <= _size);
        assert(!Empty());
        start = _freeList;
        end = start;

        for (size_t i = 0; i < size - 1; ++i)
        {
            end = GetNextObj(end);
        }
        _freeList = GetNextObj(end);
        GetNextObj(end) = nullptr;

        _size -= size;
    }

    bool Empty() const
    {
        return _freeList == nullptr;
    }

    size_t &MaxSize()
    {
        return _maxSize;
    }

    size_t Size() const
    {
        return _size;
    }

private:
    void *_freeList = nullptr; // 自由链表头指针
    size_t _maxSize = 1;
    size_t _size = 0; // 当前自由链表中内存块的数量
};

// 整体控制在最多10%左右的内碎⽚浪费
// [1,128]                  8byte对⻬               freelist[0,16)
// [128+1,1024]             16byte对⻬              freelist[16,72)
// [1024+1,81024]           128byte对⻬             freelist[72,128)
// [8*1024+1,641024]        1024byte对⻬            freelist[128,184)
// [64*1024+1,256*1024]     8*1024byte对⻬          freelist[184,208)
// 计算对象大小的对齐映射规则
class SizeClass
{
public:
    static inline size_t _RoundUp(size_t bytes, size_t alignNum)
    {
        return ((bytes + alignNum - 1) & ~(alignNum - 1));
    }

    static inline size_t RoundUp(size_t size)
    {
        if (size <= 128)
        {
            return _RoundUp(size, 8); // [1,128]字节：8字节对齐
        }
        else if (size <= 1024)
        {
            return _RoundUp(size, 16); // [129,1024]字节：16字节对齐
        }
        else if (size <= 8 * 1024)
        {
            return _RoundUp(size, 128); // [1025,8192]字节：128字节对齐
        }
        else if (size <= 64 * 1024)
        {
            return _RoundUp(size, 1024); // [8193,65536]字节：1024字节对齐
        }
        else if (size <= 256 * 1024)
        {
            return _RoundUp(size, 8 * 1024); // [65537,262144]字节：8192字节对齐
        }
        else
        {
            return _RoundUp(size, 1 << PAGE_SHIFT);
        }
    }

    static inline size_t _Index(size_t bytes, size_t align_shift)
    {
        return ((bytes + (1 << align_shift) - 1) >> align_shift) - 1;
    }

    static inline size_t Index(size_t bytes)
    {
        assert(bytes <= MAX_BYTES);

        // 每个区间有多少个链
        static int group_array[4] = {16, 56, 56, 56}; // 各区间的自由链表数量
        if (bytes <= 128)
        {
            return _Index(bytes, 3); // [1,128]字节：8字节对齐（2^3）
        }
        else if (bytes <= 1024)
        {
            // [129,1024]字节：16字节对齐（2^4），索引=区间内索引+前一区间数量
            return _Index(bytes - 128, 4) + group_array[0];
        }
        else if (bytes <= 8 * 1024)
        {
            // [1025,8192]字节：128字节对齐（2^7），索引=区间内索引+前两区间数量和
            return _Index(bytes - 1024, 7) + group_array[0] + group_array[1];
        }
        else if (bytes <= 64 * 1024)
        {
            // [8193,65536]字节：1024字节对齐（2^10），索引=区间内索引+前三区间数量和
            return _Index(bytes - 8 * 1024, 10) + group_array[0] + group_array[1] + group_array[2];
        }
        else if (bytes <= 256 * 1024)
        {
            // [65537,262144]字节：8192字节对齐（2^13），索引=区间内索引+前四区间数量和
            return _Index(bytes - 64 * 1024, 13) + group_array[0] + group_array[1] + group_array[2] + group_array[3];
        }
        else
        {
            assert(false); // 超出最大申请内存块大小
            return -1;
        }
    }

    // 一次ThreadCache从中心缓存获取多少个小对象
    static size_t NumMoveSize(size_t size)
    {
        assert(size > 0);
        // [2, 512], 一次批量移动多少个对象的(慢启动)上限值
        // 小对象一次批量上限高
        // 大对象一次批量上限低
        int num = MAX_BYTES / size;
        if (num < 2)
            num = 2;

        if (num > 512)
            num = 512;

        return num;
    }

    // 计算一次向系统获取几个页
    // 单个对象 8byte
    // ...
    // 单个对象 256byte
    static size_t NumMovePage(size_t size)
    {
        size_t num = NumMoveSize(size);
        size_t npage = num * size;

        npage >>= PAGE_SHIFT; // 向上取整到页的倍数
        if (npage == 0)
        {
            npage = 1; // 至少要申请一个页
        }
        return npage;
    }
};

// --------------------------------------------------------------------------------------------------------------------
// CentralCache 管理多个SpanList,每个SpanList管理多个Span
// PageCache需要管理多个SpanList,每个SpanList管理多个Span
// 管理多个连续页大块内存跨度结构
struct Span
{
    PAGE_ID _pageId = 0;  // 多个大块内存的起始页的页号
    size_t _numPages = 0; // 页的数量

    Span *_next = nullptr; // 指向下一个跨度的指针
    Span *_prev = nullptr; // 指向上一个跨度的指针

    size_t _useCount = 0;      // 切成好的小块内存,被分配给ThreadCache的计数器
    void *_freeList = nullptr; // 切成好的小块内存的自由链表头指针

    bool _isUsed = false; // 跨度是否被使用过
};

// 带头双向循环链表
class SpanList
{
public:
    SpanList()
    {
        _head = new Span;
        _head->_next = _head->_prev = _head;
    }

    Span *Begin() const
    {
        return _head->_next;
    }

    Span *End() const
    {
        return _head;
    }

    void Insert(Span *pos, Span *newSpan)
    {
        assert(pos != nullptr && newSpan != nullptr);

        Span *prev = pos->_prev;
        prev->_next = newSpan;
        newSpan->_prev = prev;
        newSpan->_next = pos;
        pos->_prev = newSpan;
    }

    void PushFront(Span *newSpan)
    {
        Insert(Begin(), newSpan);
    }

    void Erase(Span *pos)
    {
        assert(pos != nullptr && pos != _head);

        Span *prev = pos->_prev;
        Span *next = pos->_next;

        prev->_next = next;
        next->_prev = prev;
    }

    Span *PopFront()
    {
        Span *front = Begin();
        Erase(front);
        return front;
    }

    bool Empty() const
    {
        return _head->_next == _head;
    }

private:
    Span *_head;

public:
    std::mutex _mutex; // 跨度链表的互斥锁, 桶锁
};